﻿package net.wangit.view.chart;

import java.awt.Color;

import net.wangit.MapList;
import net.wangit.Row;
import net.wangit.framework.config.DomainsSettings;
import net.wangit.jdbc.DB;
import net.wangit.jdbc.ServerAccessException;
import net.wangit.jdbc.util.DBHelper;
import net.wangit.util.Checker;
import net.wangit.util.StringUtil;
import net.wangit.view.chart.config.ChartSettings;
import net.wangit.view.chart.impl.AreaChart;
import net.wangit.view.chart.impl.Bar3DChart;
import net.wangit.view.chart.impl.BarChart;
import net.wangit.view.chart.impl.Line3DChart;
import net.wangit.view.chart.impl.LineChart;
import net.wangit.view.chart.impl.Pie3DChart;
import net.wangit.view.chart.impl.PieChart;
import net.wangit.view.chart.impl.StackedAreaChart;
import net.wangit.view.chart.impl.StackedBar3DChart;
import net.wangit.view.chart.impl.StackedBarChart;
import net.wangit.view.chart.impl.WaterfallChart;
import net.wangit.view.chart.util.BorderUtil;
import net.wangit.view.chart.util.ColorUtil;
import net.wangit.view.chart.util.FontUtil;
import net.wangit.view.chart.util.PositionUtil;
import net.wangit.view.chart.util.StrokeUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.title.TextTitle;
import org.jfree.ui.RectangleInsets;


public class ChartProvider {

	private static Log log = LogFactory
			.getLog(net.wangit.view.chart.ChartProvider.class);
	private static final String SQL = "select * from CHART where cid=?";

	public ChartProvider() {
	}

	public static synchronized Chart getChart(String domain, String chartId) {
		if (Checker.isEmpty(domain) || Checker.isEmpty(chartId)) {
			log.error((new StringBuilder(
					"empty arguments is not acceptable: domain=")).append(
					domain).append(" chartid=").append(chartId).toString());
			return null;
		}
		chartId = chartId.toLowerCase();
		Chart chartObject = ChartCache.get(domain, chartId);
		if (chartObject == null) {
			chartObject = createChart(domain, chartId);
			ChartCache.put(domain, chartId, chartObject);
		}
		return chartObject;
	}

	private static Chart createChart(String domain, String chartId) {
		DB db = DBHelper.getDomainDB(domain);
		MapList list;
		try {
			list = db.query("select * from CHART where cid=?", chartId, 2);
		} catch (Exception e) {
			log.error((new StringBuilder("could not query unit in server: "))
					.append(domain).toString(), e);
			throw new ServerAccessException((new StringBuilder(
					"could not query unit in server: ")).append(domain)
					.toString());
		}
		if (Checker.isEmpty(list)) {
			log.error((new StringBuilder("page not found: ")).append(domain)
					.append("/").append(chartId).toString());
			throw new ChartConfigurationException((new StringBuilder(
					"chart not found: ")).append(domain).append("/").append(
					chartId).toString());
		} else {
			Row row = list.getRow(0);
			Chart chart = getChart(row);
			setBase(chart, row, domain);
			setPane(chart, row);
			setPlot(chart, row);
			setRenderer(chart, row);
			setTitle(chart, row);
			setLegend(chart, row);
			return chart;
		}
	}

	private static Chart getChart(Row row) {
		int type = row.getInt("t", 11);
		switch (type) {
		case 1: // '\001'
		{
			Chart chart = new PieChart();
			setPiePlot(chart, row);
			return chart;
		}

		case 2: // '\002'
		{
			Chart chart = new Pie3DChart();
			setPiePlot(chart, row);
			return chart;
		}

		case 11: // '\013'
		{
			Chart chart = new BarChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 12: // '\f'
		{
			Chart chart = new StackedBarChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 13: // '\r'
		{
			Chart chart = new Bar3DChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 14: // '\016'
		{
			Chart chart = new StackedBar3DChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 15: // '\017'
		{
			Chart chart = new WaterfallChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 21: // '\025'
		{
			Chart chart = new LineChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 22: // '\026'
		{
			Chart chart = new Line3DChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 31: // '\037'
		{
			Chart chart = new AreaChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}

		case 32: // ' '
		{
			Chart chart = new StackedAreaChart();
			setCategoryPlot(chart, row);
			setAxis(chart, row);
			return chart;
		}
		}
		throw new UnsupportedOperationException((new StringBuilder(
				"Unsupported chart: ")).append(type).toString());
	}

	private static void setBase(Chart chart, Row row, String domain) {
		chart.setDomain(domain);
		chart.setWidth(row.getInt("w", 500));
		chart.setHeight(row.getInt("h", 300));
		chart.setTitle(row.get("n"));
		chart.setCategoryLabel(row.get("cl"));
		chart.setValueLabel(row.get("vl"));
		chart.setDataMode(row.getInt("dm", 1));
		String datasource = row.get("d");
		if (Checker.isEmpty(datasource))
			datasource = DomainsSettings.getDatasource(domain);
		chart.setDatasource(datasource);
		chart.setQueryUnitId(row.get("qu"));
		chart.setTableName(row.get("x"));
		chart.setDataExpression(row.get("de"));
		chart.setFactory(row.get("f"));
		chart.setSetter(row.get("s"));
	}

	private static void setPane(Chart chart, Row row) {
		chart.setAntiAlias("1".equals(row.get("aa")));
		String backgroundColor = row.get("bc");
		if (!Checker.isEmpty(backgroundColor))
			chart.setBackgroundColor(ColorUtil.getColor(backgroundColor));
		chart.setBackgroundImage(row.get("bi"));
		chart.setBackgroundImageAlignment(row.getInt("bia", 15));
		chart.setBackgroundImageAlpha(row.getFloat("bial", 0.75F));
		chart.setBorderVisible("1".equals(row.get("bov")));
		String borderColor = row.get("boc");
		if (!Checker.isEmpty(borderColor))
			chart.setBorderColor(ColorUtil.getColor(borderColor));
		String borderStroke = row.get("bos");
		if (!Checker.isEmpty(borderStroke))
			chart.setBorderStroke(StrokeUtil.getStroke(Float
					.parseFloat(borderStroke)));
		chart.setPadding(new RectangleInsets(row.getInt("pt", 1), row.getInt(
				"pl", 1), row.getInt("pb", 1), row.getInt("pr", 1)));
	}

	private static void setPlot(Chart chart, Row row) {
		String colorsString = row.get("cs");
		if (!Checker.isEmpty(colorsString)) {
			String colorsArray[] = StringUtil.split(colorsString, ",");
			Color colors[] = new Color[colorsArray.length];
			for (int i = 0; i < colorsArray.length; i++)
				colors[i] = ColorUtil.getColor(colorsArray[i].trim());

			chart.setColors(colors);
		}
		chart.setTooltips("1".equals(row.get("tt")));
		chart.setToolTipFormat(row.get("ttf"));
		chart.setUrls("1".equals(row.get("urls")));
		chart.setUrl(row.get("url"));
		String plotBackgroundColor = row.get("pbc");
		if (!Checker.isEmpty(plotBackgroundColor))
			chart.setPlotBackgroundColor(ColorUtil
					.getColor(plotBackgroundColor));
		chart.setPlotForegroundAlpha(row.getFloat("pfa", 1.0F));
		chart.setPlotBackgroundAlpha(row.getFloat("pba", 1.0F));
		String plotOutlineColor = row.get("poc");
		if (!Checker.isEmpty(plotOutlineColor))
			chart.setPlotOutlineColor(ColorUtil.getColor(plotOutlineColor));
		String plotOutlineStroke = row.get("pos");
		if (!Checker.isEmpty(plotOutlineStroke))
			chart.setPlotOutlineStroke(StrokeUtil.getStroke(Float
					.parseFloat(plotOutlineStroke)));
		chart.setPlotPadding(new RectangleInsets(row.getInt("ppt", 4), row
				.getInt("ppl", 8), row.getInt("ppb", 4), row.getInt("ppr", 8)));
		chart.setItemlabelFormat(row.get("ilf"));
		String itemOutlineColor = row.get("ioc");
		if (!Checker.isEmpty(itemOutlineColor))
			chart.setItemOutlineColor(ColorUtil.getColor(itemOutlineColor));
		String setItemlabelStroke = row.get("ios");
		if (!Checker.isEmpty(setItemlabelStroke))
			chart.setItemOutlineStroke(StrokeUtil.getStroke(Float
					.parseFloat(setItemlabelStroke)));
	}

	private static void setCategoryPlot(Chart chart, Row row) {
		int orientation = row.getInt("ori", 1);
		chart.setOrientation(orientation != 1 ? PlotOrientation.HORIZONTAL
				: PlotOrientation.VERTICAL);
		chart.setDomainGridlinesVisible("1".equals(row.get("dv")));
		String domainGridlinesColor = row.get("dv");
		if (!Checker.isEmpty(domainGridlinesColor))
			chart.setDomainGridlinesColor(ColorUtil
					.getColor(domainGridlinesColor));
		String domainGridlinesStroke = row.get("ds");
		if (!Checker.isEmpty(domainGridlinesStroke))
			chart.setDomainGridlinesStroke(StrokeUtil.getStroke(Float
					.parseFloat(domainGridlinesStroke)));
		chart.setDomainGridlinesPosition(PositionUtil
				.getDomainGridlinePosition(row.getInt("dp", 2)));
		chart.setRangeGridlinesVisible("1".equals(row.get("rv")));
		String rangeGridlinesColor = row.get("rc");
		if (!Checker.isEmpty(rangeGridlinesColor))
			chart.setRangeGridlinesColor(ColorUtil
					.getColor(rangeGridlinesColor));
		String rangeGridlinesStroke = row.get("rs");
		if (!Checker.isEmpty(rangeGridlinesStroke))
			chart.setRangeGridlinesStroke(StrokeUtil.getStroke(Float
					.parseFloat(rangeGridlinesStroke)));
		chart.setAxisOffset(new RectangleInsets(row.getInt("at", 0), row
				.getInt("al", 0), row.getInt("ab", 0), row.getInt("ar", 0)));
	}

	private static void setRenderer(Chart chart, Row row) {
		chart.setItemLabelsVisible("1".equals(row.get("iv")));
		chart.setItemLabelAnchorOffset(row.getDouble("io", 2D));
		chart.setItemLabelsPosition(row.getInt("ip", 1));
	}

	private static void setAxis(Chart chart, Row row) {
		setCategoryAxis(chart, row);
		setNumberAxis(chart, row);
	}

	private static void setCategoryAxis(Chart chart, Row row) {
		chart.setCategoryAxisVisible("1".equals(row.get("cv")));
		String color = row.get("cc");
		if (!Checker.isEmpty(color))
			chart.setCategoryAxisLabelColor(ColorUtil.getColor(color));
		String font = row.get("cf", "SansSerif");
		int fontStyle = row.getInt("cfs", 0);
		int fontSize = row.getInt("cfsi", 12);
		chart.setCategoryAxisLabelFont(FontUtil.getFont(font, fontStyle,
				fontSize));
		color = row.get("clc");
		if (!Checker.isEmpty(color))
			chart.setCategoryAxisTickLabelColor(ColorUtil.getColor(color));
		font = row.get("clf", "SansSerif");
		fontStyle = row.getInt("clfs", 0);
		fontSize = row.getInt("clfsi", 10);
		chart.setCategoryAxisTickLabelFont(FontUtil.getFont(font, fontStyle,
				fontSize));
		int position = row.getInt("cp", 1);
		chart.setCategoryAxisCategoryLabelPositions(PositionUtil
				.getCategoryLabelPositions(position));
	}

	private static void setNumberAxis(Chart chart, Row row) {
		chart.setNumberAxisVisible("1".equals(row.get("nv")));
		String color = row.get("nlc");
		if (!Checker.isEmpty(color))
			chart.setNumberAxisLabelColor(ColorUtil.getColor(color));
		String font = row.get("nlf", "SansSerif");
		int fontStyle = row.getInt("nlfs", 0);
		int fontSize = row.getInt("nlfsi", 12);
		chart.setNumberAxisLabelFont(FontUtil
				.getFont(font, fontStyle, fontSize));
		color = row.get("ntlc");
		if (!Checker.isEmpty(color))
			chart.setNumberAxisTickLabelColor(ColorUtil.getColor(color));
		font = row.get("ntlf", "SansSerif");
		fontStyle = row.getInt("ntlfs", 0);
		fontSize = row.getInt("ntlfsi", 10);
		chart.setNumberAxisTickLabelFont(FontUtil.getFont(font, fontStyle,
				fontSize));
		chart.setNumberAxisUpperMargin(row.getDouble("num",
				0.10000000000000001D));
		chart.setNumberAxisLowerMargin(row.getDouble("nlm",
				0.10000000000000001D));
	}

	private static void setTitle(Chart chart, Row row) {
		chart.setTitlePosition(PositionUtil.getTitlePosition(row
				.getInt("tp", 1)));
		String titleColor = row.get("tc");
		if (!Checker.isEmpty(titleColor))
			chart.setTitleColor(ColorUtil.getColor(titleColor));
		String titleBackgroundColor = row.get("tbc");
		if (!Checker.isEmpty(titleBackgroundColor))
			chart.setTitleBackgroundColor(ColorUtil
					.getColor(titleBackgroundColor));
		String font = row.get("tf", "SansSerif");
		int fontStyle = row.getInt("tfs", 1);
		int fontSize = row.getInt("tfsi", 16);
		chart.setTitleFont(FontUtil.getFont(font, fontStyle, fontSize));
		if ("1".equals(row.get("tbo"))) {
			String color = row.get("tboc");
			double top = row.getDouble("tbot", 1.0D);
			double left = row.getDouble("tbol", 1.0D);
			double bottom = row.getDouble("tbob", 1.0D);
			double right = row.getDouble("tbor", 1.0D);
			chart.setTitleBorder(BorderUtil.getBorder(top, left, bottom, right,
					color));
		} else {
			chart.setTitleBorder(BlockBorder.NONE);
		}
		String subTitleString = row.get("ts");
		if (!Checker.isEmpty(subTitleString)) {
			TextTitle subTitle = new TextTitle(subTitleString);
			subTitle.setFont(ChartSettings.SUB_TITLE__FONT);
			chart.setSubTitle(subTitle);
		}
	}

	private static void setLegend(Chart chart, Row row) {
		chart.setLegend(row.getInt("le", 1) == 1);
		chart.setLegendPosition(PositionUtil.getTitlePosition(row.getInt("lep",
				3)));
		String legendColor = row.get("lec");
		if (!Checker.isEmpty(legendColor))
			chart.setLegendColor(ColorUtil.getColor(legendColor));
		String legendBackgroundColor = row.get("lebc");
		if (!Checker.isEmpty(legendBackgroundColor))
			chart.setLegendBackgroundColor(ColorUtil
					.getColor(legendBackgroundColor));
		String legendFont = row.get("lef");
		int legendFontStyle = row.getInt("lefs", 0);
		int legendFontSize = row.getInt("lefsi", 10);
		chart.setLegendFont(FontUtil.getFont(legendFont, legendFontStyle,
				legendFontSize));
		if ("1".equals(row.get("lebo"))) {
			String color = row.get("leboc");
			double top = row.getDouble("lebot", 1.0D);
			double left = row.getDouble("lebol", 1.0D);
			double bottom = row.getDouble("lebob", 1.0D);
			double right = row.getDouble("lebor", 1.0D);
			chart.setLegendBorder(BorderUtil.getBorder(top, left, bottom,
					right, color));
		} else {
			chart.setLegendBorder(BlockBorder.NONE);
		}
	}

	private static void setPiePlot(Chart chart, Row row) {
		chart.setPieCircular("1".equals(row.get("pc")));
		chart.setPieStartAngle(row.getDouble("psa", 90D));
		chart.setPieLabelLinksVisible("1".equals(row.get("plv")));
		chart.setPieItemOutlinesVisible("1".equals(row.get("pilv")));
		chart.setPieExplodePercents(row.get("pep"));
	}

}
